/*
 * SPDX-License-Identifier: GPL-2.0
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
 * Description:
 * Author: -
 * Create: 2021.4.19
 */

#include "ossl_knl.h"
#include "hiudk3.h"
#include "hiudk_internal.h"
/**
 * @brief 删除创建的对象
 * @details 删除创建的对象，该函数会休眠等待所有对该对象的操作完成才返回
 * @param object 对象指针
 * @retval void
 * @author
 * @date 2022-4-28
 */
void hiudk_cqm_object_delete(void *udkdev, cqm_object_s *object)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_delete != NULL))) {
        ops->cqm_ops.hiudk_cqm_object_delete(object);
        return;
    }
    pr_err("ops is NULL! \n");
    return;
}

EXPORT_SYMBOL(hiudk_cqm_object_delete);

/**
 * @brief 创建FC SRQ
 * @details
 * 队列中有效wqe个数必须要满足传入的wqe个数。因为linkwqe只能填在页尾，真实有效个数超过需求，需要告知业务多创建的个数。
 * @param udkdev 表征PF的设备指针
 * @param service_type 服务类型
 * @param object_type 对象类型
 * @param wqe_number wqe数目
 * @param wqe_size wqe大小
 * @param object_priv 对象私有信息指针
 * @retval cqm_queue_s 队列结构指针
 * @author
 * @date 2022-4-28
 */
cqm_queue_s *hiudk_cqm_object_fc_srq_create(void *udkdev, u32 service_type, cqm_object_type_e object_type,
                                            u32 wqe_number, u32 wqe_size, void *object_priv)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_fc_srq_create != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_fc_srq_create(sdk_hwdev, service_type, object_type, wqe_number,
                                                           wqe_size, object_priv);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_fc_srq_create);

/**
 * @brief 获得对象的所在function ID
 * @details 获得对象的所在function ID
 * @param object 对象指针
 * @retval >=0 function的ID
 * @retval -1 失败
 * @author
 * @date 2020-4-15
 */
s32 hiudk_cqm_object_funcid(void *udkdev, cqm_object_s *object)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return -EINVAL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_funcid != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_funcid(object);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_cqm_object_funcid);

/**
 * @brief 根据index获得object
 * @details 根据index获得object
 * @param udkdev 表征PF的设备指针
 * @param object_type 对象类型
 * @param index 支持qpn,mptn,scqn,srqn
 * @param bh 是否禁用中断下半部
 * @retval cqm_object_s *对象指针
 * @author
 * @date 2022-4-28
 */
cqm_object_s *hiudk_cqm_object_get(void *udkdev, cqm_object_type_e object_type, u32 index, bool bh)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_get != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_get(sdk_hwdev, object_type, index, bh);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_get);

/**
 * @brief 创建非RDMA业务的队列
 * @details 创建非RDMA业务的队列，此接口会休眠
 * @param udkdev 表征PF的设备指针
 * @param service_type 服务类型
 * @param object_type 对象类型
 * @param wqe_number 包含link wqe的数目
 * @param wqe_size 定长，大小为2^n
 * @param object_priv 服务层的私有结构，可以为NULL
 * @retval cqm_queue_s 队列结构指针
 * @author
 * @date 2022-4-28
 */
cqm_queue_s *hiudk_cqm_object_nonrdma_queue_create(void *udkdev, u32 service_type, cqm_object_type_e object_type,
                                                   u32 wqe_number, u32 wqe_size, void *object_priv)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_nonrdma_queue_create != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_nonrdma_queue_create(sdk_hwdev, service_type, object_type, wqe_number,
                                                                  wqe_size, object_priv);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_nonrdma_queue_create);

/**
 * @brief 获得对象buffer指定偏移处的物理地址和虚拟地址
 * @details 仅支持rdma table查找，获得对象buffer指定偏移处的物理地址和虚拟地址
 * @param object 对象指针
 * @param offset 对于rdma table，offset为index绝对编号
 * @param paddr 仅对rdma table才返回物理地址
 * @retval u8 *buffer指定偏移处的虚拟地址
 * @author
 * @date 2022-4-28
 */
u8 *hiudk_cqm_object_offset_addr(void *udkdev, cqm_object_s *object, u32 offset, dma_addr_t *paddr)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_offset_addr != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_offset_addr(object, offset, paddr);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_offset_addr);

/**
 * @brief 对象引用计数释放
 * @details cqm_object_get函数调用以后要使用该接口put，否则object释放不了
 * @param object 对象指针
 * @retval void
 * @author
 * @date 2022-4-28
 */
void hiudk_cqm_object_put(void *udkdev, cqm_object_s *object)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_put != NULL))) {
        ops->cqm_ops.hiudk_cqm_object_put(object);
        return;
    }
    pr_err("ops is NULL! \n");
    return;
}

EXPORT_SYMBOL(hiudk_cqm_object_put);

/**
 * @brief 创建QPC和MPT
 * @details 创建QPC和MPT，此接口会休眠
 * @param udkdev 表征PF的设备指针
 * @param service_type 服务类型
 * @param object_type 对象类型
 * @param object_size 对象大小，单位Byte
 * @param object_priv 服务层的私有结构，可以为NULL
 * @param index 根据该值申请预留的qpn，如果要自动分配需填入CQM_INDEX_INVALID
 * @retval cqm_qpc_mpt_s QPC/MPT结构指针
 * @author
 * @date 2022-4-28
 */
cqm_qpc_mpt_s *hiudk_cqm_object_qpc_mpt_create(void *udkdev, u32 service_type, cqm_object_type_e object_type,
                                               u32 object_size, void *object_priv, u32 index, bool low2bit_align_en)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_qpc_mpt_create != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_qpc_mpt_create(sdk_hwdev, service_type, object_type, object_size,
                                                            object_priv, index, low2bit_align_en);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_qpc_mpt_create);

/**
 * @brief 创建RDMA业务的队列
 * @details 创建RDMA业务的队列，此接口会休眠
 * @param udkdev 表征PF的设备指针
 * @param service_type 服务类型
 * @param object_type 对象类型
 * @param object_size 对象大小
 * @param object_priv 服务层的私有结构，可以为NULL
 * @param room_header_alloc 是否要申请queue room和header空间
 * @retval cqm_queue_s 队列结构指针
 * @author
 * @date 2022-4-28
 */
cqm_queue_s *hiudk_cqm_object_rdma_queue_create(void *udkdev, u32 service_type, cqm_object_type_e object_type,
    u32 object_size, void *object_priv, bool room_header_alloc, u32 xid)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_rdma_queue_create != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_rdma_queue_create(sdk_hwdev, service_type, object_type, object_size,
                                                               object_priv, room_header_alloc, xid);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_rdma_queue_create);

/**
 * @brief 创建RDMA业务的mtt和rdmarc
 * @details 创建RDMA业务的mtt和rdmarc
 * @param udkdev 表征PF的设备指针
 * @param service_type 服务类型
 * @param object_type 对象类型
 * @param index_base 起始index编号
 * @param index_number index数量
 * @retval cqm_mtt_rdmarc_s MTT/RDMARC结构指针
 * @author
 * @date 2022-4-28
 */
cqm_mtt_rdmarc_s *hiudk_cqm_object_rdma_table_get(void *udkdev, u32 service_type, cqm_object_type_e object_type,
                                                  u32 index_base, u32 index_number)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_rdma_table_get != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_rdma_table_get(sdk_hwdev, service_type, object_type, index_base,
                                                            index_number);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_rdma_table_get);

/**
 * @brief 创建RQ
 * @details 在使用SRQ时,RQ队列创建
 * @param udkdev 表征PF的设备指针
 * @param service_type 服务类型
 * @param object_type 对象类型
 * @param init_rq_num container数目
 * @param container_size container大小
 * @param wqe_size wqe大小
 * @param object_priv 对象私有信息指针
 * @retval cqm_queue_s 队列结构指针
 * @author
 * @date 2022-4-28
 */
cqm_queue_s *hiudk_cqm_object_recv_queue_create(void *udkdev, u32 service_type, cqm_object_type_e object_type,
    u32 init_rq_num, u32 container_size, u32 wqe_size, void *object_priv)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_recv_queue_create != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_recv_queue_create(sdk_hwdev, service_type, object_type, init_rq_num,
                                                               container_size, wqe_size, object_priv);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_recv_queue_create);

/**
 * @brief 给对象申请一块新空间
 * @details
 * 目前只对roce业务有用，调整CQ的buffer大小，但cqn和cqc不变，申请新的buffer空间，不释放旧buffer空间，当前有效buffer仍为旧buffer
 * @param object 对象指针
 * @param object_size 新buffer大小
 * @retval 0 成功
 * @retval -1 失败
 * @author
 * @date 2022-4-28
 */
s32 hiudk_cqm_object_resize_alloc_new(void *udkdev, cqm_object_s *object, u32 object_size)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return -EINVAL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_resize_alloc_new != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_resize_alloc_new(object, object_size);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_cqm_object_resize_alloc_new);

/**
 * @brief 给对象释放新申请buffer空间
 * @details 本函数释放新申请buffer空间，用于业务的异常处理分支
 * @param object 对象指针
 * @retval void
 * @author
 * @date 2022-4-28
 */
void hiudk_cqm_object_resize_free_new(void *udkdev, cqm_object_s *object)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_resize_free_new != NULL))) {
        ops->cqm_ops.hiudk_cqm_object_resize_free_new(object);
        return;
    }
    pr_err("ops is NULL! \n");
    return;
}

EXPORT_SYMBOL(hiudk_cqm_object_resize_free_new);

/**
 * @brief 给对象释旧buffer空间
 * @details 本函数释放旧的buffer，并将当前有效buffer设置为新buffer
 * @param object 对象指针
 * @retval void
 * @author
 * @date 2022-4-28
 */
void hiudk_cqm_object_resize_free_old(void *udkdev, cqm_object_s *object)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_resize_free_old != NULL))) {
        ops->cqm_ops.hiudk_cqm_object_resize_free_old(object);
        return;
    }
    pr_err("ops is NULL! \n");
    return;
}

EXPORT_SYMBOL(hiudk_cqm_object_resize_free_old);

/**
 * @brief srq申请新的container，创建后好挂链
 * @details srq申请新的container，创建后好挂链
 * @param common 队列结构指针
 * @retval 0 成功
 * @retval -1 失败
 * @author
 * @date 2022-4-28
 */
s32 hiudk_cqm_object_share_recv_queue_add_container(void *udkdev, cqm_queue_s *common)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return -EINVAL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_share_recv_queue_add_container != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_share_recv_queue_add_container(common);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_cqm_object_share_recv_queue_add_container);

/**
 * @brief 创建TOE业务的SRQ
 * @details 创建TOE业务的SRQ
 * @param udkdev 表征PF的设备指针
 * @param service_type 服务类型
 * @param object_type 对象类型
 * @param container_number container数目
 * @param container_size container大小
 * @param wqe_size wqe大小
 * @retval cqm_queue_s 队列结构指针
 * @author
 * @date 2022-4-28
 */
cqm_queue_s *hiudk_cqm_object_share_recv_queue_create(void *udkdev, u32 service_type, cqm_object_type_e object_type,
    u32 container_number, u32 container_size, u32 wqe_size)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return NULL;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_share_recv_queue_create != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_share_recv_queue_create(sdk_hwdev, service_type, object_type,
            container_number, container_size, wqe_size);
    }
    pr_err("ops is NULL! \n");
    return NULL;
}

EXPORT_SYMBOL(hiudk_cqm_object_share_recv_queue_create);

/**
 * @brief srq申请新的container，创建后不挂链，由业务完成挂链
 * @details srq申请新的container，创建后不挂链，由业务完成挂链
 * @param common 队列结构指针
 * @param container_addr 返回的container地址
 * @retval 0 成功
 * @retval -1 失败
 * @author
 * @date 2022-4-28
 */
s32 hiudk_cqm_object_srq_add_container_free(void *udkdev, cqm_queue_s *common, u8 **container_addr)
{
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return -EINVAL;
    }

    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_object_srq_add_container_free != NULL))) {
        return ops->cqm_ops.hiudk_cqm_object_srq_add_container_free(common, container_addr);
    }
    pr_err("ops is NULL! \n");
    return -EINVAL;
}

EXPORT_SYMBOL(hiudk_cqm_object_srq_add_container_free);

/**
 * @brief 是否需要安全内存
 * @details 此接口用于判断是否需要申请安全内存
 * @param udkdev 表征PF/VF的设备指针
 * @retval true 支持
 * @retval false 不支持
 * @author
 * @date 2023-09-23
 */
bool hiudk_cqm_need_secure_mem(void *udkdev)
{
    void *sdk_hwdev = NULL;
    struct hiudk_ops *ops = NULL;

    if (unlikely(!CHECK_UDK_DEV(udkdev))) {
        pr_err("udkdev is error! \n");
        return false;
    }

    sdk_hwdev = GET_SDKHWDEV_FROM_HIUDKHWDEV(udkdev);
    ops = GET_SDKOPS_FROM_HIUDKHWDEV(udkdev);
    if (likely((ops != NULL) && (ops->cqm_ops.hiudk_cqm_need_secure_mem != NULL))) {
        return ops->cqm_ops.hiudk_cqm_need_secure_mem(sdk_hwdev);
    }
    pr_err("ops is NULL! \n");
    return false;
}

EXPORT_SYMBOL(hiudk_cqm_need_secure_mem);